package edu.scnu.fans.fingertip.common.web;

import edu.scnu.fans.fingertip.common.api.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;


/**
 * 处理全局异常
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

	/**
	 * 参数异常处理
	 */
	@ExceptionHandler(ConstraintViolationException.class)
	@ResponseBody
	public ApiResponse<?> handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
		log.error("参数异常1", e);
        List<String> msgList = new ArrayList<>();

		for (ConstraintViolation<?> cvl : e.getConstraintViolations()) {
			msgList.add(cvl.getMessageTemplate());
		}

		return this.bindingError(String.join(",", msgList));
	}

	@ExceptionHandler(BindException.class)
	@ResponseBody
	public ApiResponse<?> handleBindingException(BindException e) {
		log.error("参数异常2", e);

		return this.bindingError(this.bindingErrorMessage(e.getBindingResult()));
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseBody
	public ApiResponse<?> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) {
		log.error("参数异常3", e);

		return this.bindingError(this.bindingErrorMessage(e.getBindingResult()));
	}

	private String bindingErrorMessage(BindingResult bindingResult) {
		return bindingResult.getFieldErrors()
				.stream()
				.map(fieldError -> "请求参数字段 " + fieldError.getField() + " 有误， 原因：" + fieldError.getDefaultMessage())
				.findFirst()
				.orElse("未知参数错误");
	}

	/**
	 * 绑定参数错误
	 */
	private ApiResponse<?> bindingError(String message) {
		return new ApiResponse<>(460, message, new Object());
	}

	/**
	 * 业务异常处理
	 */
	@ExceptionHandler(BusinessException.class)
	@ResponseBody
	public ApiResponse<?> handlerBusinessException(BusinessException e) {
		log.error("业务异常", e);
		return new ApiResponse<>(470, e.getMessage(), new Object());
	}

	/**
	 * 全局异常
	 */
	@ExceptionHandler(Throwable.class)
	@ResponseBody
	public ApiResponse<?> handlerThrowable(Throwable e) {
		log.error("全局异常", e);

		return new ApiResponse<>(500, "服务器内部错误", new Object());

	}
}